The goal of this assignment was to create a simulation of a microwave oven, heating a plate of food, using the FDTD method. The simulation consists of a microwave oven which contains a plate of food, a piece of meat and two potatoes. Dimensions and properties of these objects are presented in the table below:
| Object | Shape | Radius | Height | 915Mhz | 2450MHz | 915MHz | 2450MHz |
|---|---|---|---|---|---|---|---|
| Ceramic Plate | Cylindrical | 14cm | 1cm | 6 | 6 | 0.001 S/m | 0.001 S/m |
| Meat | Cylindrical | 8cm | 2cm | 55 | 52 | 0.95 S/m | 1.74 S/m |
| Potato | Spherical | 2cm | - | 65 | 54 | 1.02 S/m | 2.18 S/m |
Four simulations took place, with the plate located on the floor of the oven. In the initial simulation, the placement of the objects was as in the image below:
Initial Placement of objects in the oven
The plate was then rotated clockwise by three times and the mean value of SAR (Specific Absorption Rate) was calculated for each object and for each layout.
Note: for more information on how to run this notebook see here
The dimensions of the simulated oven were chosen as (), and the source is introduced as a rectangle, placed on a side of the oven. The source's dimensions are and its "lower-left" corner is at a height of 9cm and width of 7cm.
In order to create graphs of the simulation, the program is run once below, with further explanation of how it works following later in the report
%%capture
from micwave.src.main import run
sar915, ovens915 = run(915);
sar2450, ovens2450 = run(2450);
import plotly.graph_objects as go
import numpy as np
from micwave.util.config import cfg
from micwave.util.draw_helpers import draw_walls, draw_objects, draw_source, update_layout_grid
fig = go.Figure()
draw_walls(fig)
draw_objects(fig, ovens915[0].obj_indices)
draw_source(fig, cfg)
update_layout_grid(fig)
fig.show()
In the above figure, the simulation space is presented in its initial state.
The walls used in this simulation are all PEC boundaries and the source follows the equation:
where is the power of the source (in this case ), is the distances from the "lower left" corner of the source and is the angular frequency of the source.
from micwave.util.draw_helpers import draw_source_snap
f = draw_source_snap([ovens915[0].heatmaps, ovens2450[0].heatmaps])
f.show()
SAR was calculated using the following formula:
where is the electrical conductivity of each object, is the RMS electric field, is the density of each object and their volume.
In order to obtain a better estimation of the RMS electric field before calculating the SAR, the simulation had to reach a steady state, at which point the amplitude of the electric fields stabilized. This was calculated by measuring the RSS of the electric fields a single voxel over time (figures below) and estimating a timestep after which the amplitude can me considered stable. Measurements over a timestep of 800 (over ~3N periods) were taken into account for the calculation of the RMS electric fields (arbitrarily) as in the absence of a waveguide for the source the electric field never fully stabilized, but after that point it reached a satisfactory stability. The figure below demonstrates the RSS electric fields for a voxel located at grid point (50, 50, 50).
from micwave.util.draw_helpers import draw_steady
f = draw_steady([ovens915[2], ovens2450[1]])
f.show()
After the 800-timestep mark, the maximum absolute value of each electric field on every voxel was measured for the remaining duration of the simulation, and the SAR was calculated based on those maximum values for each object. The formula used for the calculation of SAR computationally was:
where is the volume of a single voxel and is the sum of the squares of the electric fields of the voxels the object occupies.
The measured SAR values for all angles for both simulations (f=915MHz and f=2450MHz) are presented below. All SAR measurements are in .
f=915MHz:
| Angle | 0.0 | 90.0 | 180.0 | 270.0 | μ | σ | σ/μ % |
|---|---|---|---|---|---|---|---|
| plate | 6.042237e-05 | 5.558224e-05 | 6.277633e-05 | 5.670388e-05 | 5.88712e-05 | 2.8797e-06 | 4.891525 |
| burger | 0.01301115 | 0.01576731 | 0.01554798 | 0.01211011 | 0.01410914 | 0.001582835 | 11.21851 |
| potato1 | 0.01689146 | 0.01001666 | 0.008335003 | 0.01575852 | 0.01275041 | 0.003645759 | 28.59327 |
| potato2 | 0.01250087 | 0.007788162 | 0.01353071 | 0.018322 | 0.01303544 | 0.003742081 | 28.70699 |
f=2450MHz:
| AVG SAR | 0.0 | 90.0 | 180.0 | 270.0 | μ | σ | σ/μ % |
|---|---|---|---|---|---|---|---|
| plate | 0.0002546722 | 0.0002591962 | 0.0001602273 | 0.0002305645 | 0.000226165 | 3.959438e-05 | 17.50685 |
| burger | 0.06832147 | 0.07854278 | 0.08058403 | 0.08533318 | 0.07819537 | 0.006210245 | 7.941961 |
| potato1 | 0.1390809 | 0.1117559 | 0.06158744 | 0.0571912 | 0.09240386 | 0.03443411 | 37.2648 |
| potato2 | 0.1533864 | 0.06377602 | 0.04788479 | 0.1434544 | 0.1021254 | 0.04676668 | 45.7934 |
The piece of meat (burger) has a much lower variation in its SAR values than the two potatoes, which could possibly be explained by the fact that its position always near the center of the plate and does not change as drastically as the position of the potatoes. Therefore, in every rotation of the plate, a similar electric field is introduced in the meat or at least parts of it, while the potatoes at no point are affected by the same fields, as the voxels they occupy are never the same.
from micwave.util.helpers import formatted_output
print("f=915MHz")
formatted_output(sar915)
print("\n\nf=2450MHz")
formatted_output(sar2450)
f=915MHz
Printing Results...
AVG SAR 0.0 90.0 180.0 270.0 μ σ σ/μ %
plate 6.042237e-05 5.558224e-05 6.277633e-05 5.670388e-05 5.88712e-05 2.8797e-06 4.891525
burger 0.01301115 0.01576731 0.01554798 0.01211011 0.01410914 0.001582835 11.21851
potato1 0.01689146 0.01001666 0.008335003 0.01575852 0.01275041 0.003645759 28.59327
potato2 0.01250087 0.007788162 0.01353071 0.018322 0.01303544 0.003742081 28.70699
f=2450MHz
Printing Results...
AVG SAR 0.0 90.0 180.0 270.0 μ σ σ/μ %
plate 0.0002546722 0.0002591962 0.0001602273 0.0002305645 0.000226165 3.959438e-05 17.50685
burger 0.06832147 0.07854278 0.08058403 0.08533318 0.07819537 0.006210245 7.941961
potato1 0.1390809 0.1117559 0.06158744 0.0571912 0.09240386 0.03443411 37.2648
potato2 0.1533864 0.06377602 0.04788479 0.1434544 0.1021254 0.04676668 45.7934
Some figures of the final states of the E fields are presented below, for all angles and several planes.
from micwave.util.draw_helpers import draw_E
E_snap915 = [oven.E for oven in ovens915]
E_snap2450 = [oven.E for oven in ovens2450]
E_max915 = [oven.max_E for oven in ovens915]
f = draw_E(E_snap915, offset=30, f=915, Eaxis="y", draw_plane="z")
f.show()
f1 = draw_E(E_snap915, offset=169, f=915, Eaxis="y", draw_plane="y")
f1.show()
f2 = draw_E(E_snap2450, offset=30, f=2450, Eaxis="y", draw_plane="z")
f2.show()
f3 = draw_E(E_snap2450, offset=30, f=2450, Eaxis="rss", draw_plane="z")
f3.show()
# Maximum Energies after 800-timestep.
f4 = draw_E(E_max915, offset=30, f=915, Eaxis="y", draw_plane="z")
f4.show()
The program that implements the simulation was written in python, making heavy use of the numpy library. The directory structure is the following:
em_proj_final
.
├── Dockerfile
├── images/
├── LICENSE
├── micwave
│ ├── src
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── microwave_oven.py
│ └── util
│ ├── config.py
│ ├── draw_helpers.py
│ ├── helpers.py
│ ├── __init__.py
│ └── masks.py
├── README.md
├── setup.py
└── TsourosReportEM.ipynb
Dockerfile is used for building the docker image for this project and notebook (explained in the chapter below).images is a directory containg images used in this notebook.setup.py contains the install script for this project.TsourosReportEM.ipynb is this notebook.The microwave_oven.py file contains the MicrowaveOven
class which contains most of the logic used in this simulation. More
specifically, it initializes all fields, adds objects to the "grid" and
implements the FDTD method, updating E and H fields.
main.py acts as an entrypoint for this program, rotating the plate and keeping track of the results.
config.py is the configuration file for this project, containing all required initial data (i.e. and values for objects), the dimensions of the oven, the source and the objects, constants and more. It creates a dataclass.
helpers.py is a collection of helper functions, used at various points in this project. Some examples are gpt which takes an input (of length) in meters and "translates" it to grid points based on grid spacing, or get_coefficients which calculates and returns the coefficients for the objects in the grid.
masks.py is another collection of functions used for
creating a mask for the objects to be added in the grid. In order to add
an object to the grid, a rectanglular object is created around it first
and then the mask is applied on each coefficient field.
draw_helpers.py contains functions used solely for visualization in this notebook.
From the project's root directory run:
docker build --tag microwave_tsouros . # Might require sudo
docker run -p 8888:8888 -t microwave_tsouros # Port forwarding to a local ip is required to access the nb.
From the terminal output, click the link provided (pointing to localhost) by jupyter containing the token:

From the project's root directory run (preferrably in a virtual environment):
pip install -e .[pres]
When the installation finishes, the notebook can be run with:
jupyter notebook TsourosReportEM.ipynb
Run the simulation without accessing the notebook. Defaults to 915MHz if no arguments are provided (with the -f/--frequency flag).
From the project's root directory run:
docker build --tag microwave_tsouros . # Might require sudo
docker run -t microwave_tsouros mic [-f/--frequency 915/2450]
From the project's root directory (preferrably in a virtual environment):
pip install -e .
mic [-f/--frequency 915/2450]
# OR
python micwave/src/main.py [-f/--frequency 915/2450]